﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading.Tasks;
using static System.Windows.Forms.LinkLabel;

namespace PointAsLine
{

    internal class CircleLineHandler
    {
        // 阈值，用于判断点是否在一条直线上
        public static float Threshold = 0.2f; // 可以根据需要调整这个值

        // 新增方法：对点序列Pi到Pj进行直线拟合并确定最佳起点和终点
        public static Tuple<PointF2G, PointF2G> FitLineAndFindEndpoints(Polyline points, int startIndex, int endIndex)
        {
            if (points == null || endIndex - startIndex < 1)
            {
                throw new ArgumentException("Invalid point range");
            }

            // 提取子序列
            var subPoints = points.Points.Skip(startIndex).Take(endIndex - startIndex + 1).ToList();

            // 1. 拟合最佳直线 (使用最小二乘法)
            var line = new Line(0, 0);
            line.FitLineLeastSquares(subPoints);

           
            // 2. 计算所有点在直线上的投影参数r
            List<Tuple<PointF2G, double>> projectedPoints = new List<Tuple<PointF2G, double>>();

            foreach (var point in subPoints)
            {
                var r = line.ComputeR(point);
                projectedPoints.Add(Tuple.Create(point, r));
            }

            // 3. 找到r最大和最小的点
            var sortedPoints = projectedPoints.OrderBy(p => p.Item2).ToList();
            var minPoint = sortedPoints.First().Item1;
            var maxPoint = sortedPoints.Last().Item1;

            if(PointFFunc.Distance(maxPoint, points[endIndex])< PointFFunc.Distance(minPoint, points[endIndex]))
            {
                // 4. 返回起点和终点 (r最小为起点，r最大为终点)
                return Tuple.Create(minPoint, maxPoint);
            }
            else
            {
                // 4. 返回起点和终点 (r最小为起点，r最大为终点)
                return Tuple.Create(maxPoint, minPoint);
            }
        }


        // 其他已有方法保持不变...
        public static List<Polyline> Process(List<Polyline> segments)
        {
            List<Polyline> result = new List<Polyline>();

            for(var i=0; i < segments.Count;i++)
            {
                var segment= segments[i];
                result.Add(Process(segment));
            }

            return result;
        }

        public static Polyline Process(Polyline segment)
        {
            if (segment == null || segment.Count < 3)
            {
                return segment;
            }

            while(true)
            {
                var hasUpdate = false;
                for (var i = segment.Count - 1; i > 0; i--)
                {
                    if (PointFFunc.Distance(segment[i], segment[i - 1]) < 1)
                    {
                        hasUpdate=true;
                        segment.RemoveAt(i);
                    }
                }
                if (hasUpdate == false)
                    break;
            }
            

            List<PointF2G> result = new List<PointF2G>();
            int startIndex = 0;
            result.Add(segment[startIndex]);

            while (startIndex < segment.Count - 2)
            {
                int endIndex = FindEndIndex(segment, startIndex);
                //这不能用直角判断

                if (endIndex > startIndex + 1)
                {
                    // 使用新方法拟合直线并确定最佳起点和终点
                    var endpoints = FitLineAndFindEndpoints(segment, startIndex, endIndex);

                    // 替换结果列表中的最后一个点(可能是部分拟合的)
                    if (result.Count > 0)
                    {
                        result[result.Count - 1] = endpoints.Item1;
                    }
                    else
                    {
                        result.Add(endpoints.Item1);
                    }

                    result.Add(endpoints.Item2);
                    startIndex = endIndex;
                }
                else
                {
                    result.Add(segment[startIndex + 1]);
                    startIndex++;
                }
            }

            if (startIndex < segment.Count)
            {
                result.Add(segment[segment.Count - 1]);
            }

            return new Polyline() { Points = result, GroupIndex = segment.GroupIndex };
        }

        private static int FindEndIndex(Polyline segment, int startIndex)
        {
            int endIndex = startIndex + 2;

            while (endIndex < segment.Count &&
                   ArePointsCollinear(segment, startIndex, endIndex))
            {
                endIndex++;
            }

            return endIndex - 1;
        }

        private static bool ArePointsCollinear(Polyline segment, int startIndex, int endIndex)
        {
            if (endIndex - startIndex < 2) return false;

            // 使用新方法拟合直线
            var endpoints = FitLineAndFindEndpoints(segment, startIndex, endIndex);
            PointF2G p1 = endpoints.Item1;
            PointF2G p2 = endpoints.Item2;

            // 检查中间所有点是否接近p1-p2线段
            for (int i = startIndex ; i <=endIndex; i++)
            {
                if (!IsPointNearLineSegment(segment[i], p1, p2))
                {
                    return false;
                }
            }
            //如果endIndex+1-->endIndex垂直于p1,p2,并且
            {
                var endIndexP1 = endIndex + 1;
                if (endIndexP1 < segment.Count)
                {
                    var p4 = segment[endIndexP1];
                    var deg = CornerReg.CalculateAngle((p1, p2), (segment[endIndex], segment[endIndexP1]));
                    if (deg > 70 && IsPointNearLineSegment(p4, p1, p2)==false)
                    {
                        return false;
                    }
                }
            }
 
            return true;
        }


        private static bool IsPointNearLineSegment(PointF2G p, PointF2G p1, PointF2G p2)
        {
            float distance = DistancePointToLineSegment(p, p1, p2);
            return distance <= Threshold;
        }

        private static float DistancePointToLineSegment(PointF2G p, PointF2G p1, PointF2G p2)
        {
            float dx = p2.X - p1.X;
            float dy = p2.Y - p1.Y;

            if (dx == 0 && dy == 0)
            {
                return PointFFunc.Distance(p, p1);
            }

            float segmentLengthSquared = dx * dx + dy * dy;
            float vx = p.X - p1.X;
            float vy = p.Y - p1.Y;
            float t = (vx * dx + vy * dy) / segmentLengthSquared;

            if (t < 0) return PointFFunc.Distance(p, p1);
            if (t > 1) return PointFFunc.Distance(p, p2);

            float projX = p1.X + t * dx;
            float projY = p1.Y + t * dy;
            return PointFFunc.Distance(p, new PointF2G(projX, projY));
        }

    }
}
